/*
 * The contents of this file are subject to the Mozilla Public License
 * Version 1.1 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
 * License for the specific language governing rights and limitations
 * under the License.
 * 
 * The Original Code is iSQL-Viewer, A Mutli-Platform Database Tool.
 *
 * The Initial Developer of the Original Code is iSQL-Viewer, A Mutli-Platform Database Tool.
 * Portions created by Mark A. Kobold are Copyright (C) 2000-2007. All Rights Reserved.
 *
 * Contributor(s): 
 *  Mark A. Kobold [mkobold <at> isqlviewer <dot> com].
 *  
 * If you didn't download this code from the following link, you should check
 * if you aren't using an obsolete version: http://www.isqlviewer.com
 */
package org.isqlviewer.sql;

import java.io.InputStream;
import java.io.Reader;
import java.math.BigDecimal;
import java.net.URL;
import java.sql.Array;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.Date;
import java.sql.ParameterMetaData;
import java.sql.PreparedStatement;
import java.sql.Ref;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.Calendar;

/**
 * TODO Add WrappedPreparedStatement Overview JavaDoc.
 * <p>
 * 
 * @author Mark A. Kobold &lt;mkobold at isqlviewer dot com&gt;
 * @version 1.0
 */
class PreparedStatementWrapper extends StatementWrapper implements PreparedStatement {

    private PreparedStatement proxy;
    private boolean hasLogged = false;

    public PreparedStatementWrapper(ConnectionWrapper connection, PreparedStatement stmt, String sql) {

        super(connection, stmt, sql);
        this.proxy = stmt;
    }

    public void setCharacterStream(int parameterIndex, Reader reader, int length) throws SQLException {

        connection.updateLastAccess();
        try {
            proxy.setCharacterStream(parameterIndex, reader, length);
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "setCharacterStream(int,Reader,int)"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "setCharacterStream(int,Reader,int)");
            throw sqle;
        }
    }

    @Override
    public void close() throws SQLException {

        try {
            proxy.clearParameters();
        } catch (Throwable t) {
            error(messages.format("DataSource.GeneralMethodError", "clearParameters()"), t);
        }
        super.close();

    }

    public ResultSet executeQuery() throws SQLException {

        connection.updateLastAccess();
        try {
            logQuery();
            ResultSetWrapper wrs = new ResultSetWrapper(this, proxy.executeQuery());
            openCursors.add(wrs);
            return wrs;
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "executeQuery()"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "executeQuery()");
            throw sqle;
        }
    }

    public int executeUpdate() throws SQLException {

        connection.updateLastAccess();
        try {
            logQuery();
            return proxy.executeUpdate();
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "executeUpdate()"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "executeUpdate()");
            throw sqle;
        }
    }

    public ParameterMetaData getParameterMetaData() throws SQLException {

        connection.updateLastAccess();
        try {
            return proxy.getParameterMetaData();
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "getParameterMetaData()"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "getParameterMetaData()");
            throw sqle;
        }
    }

    public void setURL(int parameterIndex, URL x) throws SQLException {

        connection.updateLastAccess();
        try {
            proxy.setURL(parameterIndex, x);
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "setURL(int, URL)"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "setURL(int, URL)");
            throw sqle;
        }
    }

    public void addBatch() throws SQLException {

        connection.updateLastAccess();
        try {
            proxy.addBatch();
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "addBatch()"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "addBatch()");
            throw sqle;
        }
    }

    public void clearParameters() throws SQLException {

        connection.updateLastAccess();
        try {
            proxy.clearParameters();
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "clearParameters()"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "clearParameters()");
            throw sqle;
        }
    }

    public boolean execute() throws SQLException {

        connection.updateLastAccess();
        try {
            logQuery();
            return proxy.execute();
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "execute()"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "execute()");
            throw sqle;
        }
    }

    public ResultSetMetaData getMetaData() throws SQLException {

        connection.updateLastAccess();
        try {
            return proxy.getMetaData();
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "getMetaData()"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "getMetaData()");
            throw sqle;
        }
    }

    public void setArray(int i, Array x) throws SQLException {

        connection.updateLastAccess();
        try {
            proxy.setArray(i, x);
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "setArray(int, Array)"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "setArray(int, Array)");
            throw sqle;
        }
    }

    public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException {

        connection.updateLastAccess();
        try {
            proxy.setAsciiStream(parameterIndex, x, length);
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "setAsciiStream(int,InputStream,int)"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "setAsciiStream(int,InputStream,int)");
            throw sqle;
        }
    }

    public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException {

        connection.updateLastAccess();
        try {
            proxy.setBigDecimal(parameterIndex, x);
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "setBigDecimal(int,BigDecimal)"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "setBigDecimal(int,BigDecimal)");
            throw sqle;
        }
    }

    public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException {

        connection.updateLastAccess();
        try {
            proxy.setBinaryStream(parameterIndex, x, length);
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "setBinaryStream(int,InputStream,int)"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "setBinaryStream(int,InputStream,int)");
            throw sqle;
        }
    }

    public void setBlob(int i, Blob x) throws SQLException {

        connection.updateLastAccess();
        try {
            proxy.setBlob(i, x);
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "setBlob(int,Blob)"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "setBlob(int,Blob)");
            throw sqle;
        }
    }

    public void setBoolean(int parameterIndex, boolean x) throws SQLException {

        connection.updateLastAccess();
        try {
            proxy.setBoolean(parameterIndex, x);
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "setBoolean(int,boolean)"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "setBoolean(int,boolean)");
            throw sqle;
        }
    }

    public void setByte(int parameterIndex, byte x) throws SQLException {

        connection.updateLastAccess();
        try {
            proxy.setByte(parameterIndex, x);
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "setByte(int,byte)"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "setByte(int,byte)");
            throw sqle;
        }
    }

    public void setBytes(int parameterIndex, byte[] x) throws SQLException {

        connection.updateLastAccess();
        try {
            proxy.setBytes(parameterIndex, x);
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "setBytes(int,byte[]))"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "setBytes(int,bytes[])");
            throw sqle;
        }
    }

    public void setClob(int i, Clob x) throws SQLException {

        connection.updateLastAccess();
        try {
            proxy.setClob(i, x);
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "setClob(int,Clob)"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "setClob(int,Clob)");
            throw sqle;
        }
    }

    public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException {

        connection.updateLastAccess();
        try {
            proxy.setDate(parameterIndex, x, cal);
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "setDate(int,Date,Calendar)"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "setDate(int,Date,Calendar)");
            throw sqle;
        }
    }

    public void setDate(int parameterIndex, Date x) throws SQLException {

        connection.updateLastAccess();
        try {
            proxy.setDate(parameterIndex, x);
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "setDate(int,Date)"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "setDate(int,Date)");
            throw sqle;
        }
    }

    public void setDouble(int parameterIndex, double x) throws SQLException {

        connection.updateLastAccess();
        try {
            proxy.setDouble(parameterIndex, x);
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "setDouble(int,double)"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "setDouble(int,double)");
            throw sqle;
        }
    }

    public void setFloat(int parameterIndex, float x) throws SQLException {

        connection.updateLastAccess();
        try {
            proxy.setFloat(parameterIndex, x);
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "setFloat(int,float)"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "setFloat(int,float)");
            throw sqle;
        }
    }

    public void setInt(int parameterIndex, int x) throws SQLException {

        connection.updateLastAccess();
        try {
            proxy.setInt(parameterIndex, x);
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "setInt(int,int)"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "setInt(int,int)");
            throw sqle;
        }
    }

    public void setLong(int parameterIndex, long x) throws SQLException {

        connection.updateLastAccess();
        try {
            proxy.setLong(parameterIndex, x);
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "setLong(int,long)"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "setLong(int,long)");
            throw sqle;
        }
    }

    public void setNull(int paramIndex, int sqlType, String typeName) throws SQLException {

        connection.updateLastAccess();
        try {
            proxy.setNull(paramIndex, sqlType, typeName);
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "setNull(int,int,String)"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "setNull(int,int,String))");
            throw sqle;
        }
    }

    public void setNull(int parameterIndex, int sqlType) throws SQLException {

        connection.updateLastAccess();
        try {
            proxy.setNull(parameterIndex, sqlType);
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "setNull(int,int)"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "setNull(int,int)");
            throw sqle;
        }
    }

    public void setObject(int parameterIndex, Object x, int targetSqlType, int scale) throws SQLException {

        connection.updateLastAccess();
        try {
            proxy.setObject(parameterIndex, x, targetSqlType, scale);
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "setObject(int,Object,int,int)"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "setObject(int,Object,int,int)");
            throw sqle;
        }
    }

    public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException {

        connection.updateLastAccess();
        try {
            proxy.setObject(parameterIndex, x, targetSqlType);
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "setObject(int,Object,int)"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "setObject(int,Object,int)");
            throw sqle;
        }
    }

    public void setObject(int parameterIndex, Object x) throws SQLException {

        connection.updateLastAccess();
        try {
            proxy.setObject(parameterIndex, x);
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "setObject(int,Object)"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "setObject(int,Object)");
            throw sqle;
        }
    }

    public void setRef(int i, Ref x) throws SQLException {

        connection.updateLastAccess();
        try {
            proxy.setRef(i, x);
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "setRef(int,Ref)"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "setRef(int,Ref)");
            throw sqle;
        }
    }

    public void setShort(int parameterIndex, short x) throws SQLException {

        connection.updateLastAccess();
        try {
            proxy.setShort(parameterIndex, x);
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "setShort(int,short)"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "setShort(int,short)");
            throw sqle;
        }
    }

    public void setString(int parameterIndex, String x) throws SQLException {

        connection.updateLastAccess();
        try {
            proxy.setString(parameterIndex, x);
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "setString(int,String)"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "setString(int,String)");
            throw sqle;
        }
    }

    public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException {

        connection.updateLastAccess();
        try {
            proxy.setTime(parameterIndex, x, cal);
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "setTime(int,Time,Calendar)"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "setTime(int,Time,Calendar)");
            throw sqle;
        }
    }

    public void setTime(int parameterIndex, Time x) throws SQLException {

        connection.updateLastAccess();
        try {
            proxy.setTime(parameterIndex, x);
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "setTime(int,Time)"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "setTime(int,Time)");
            throw sqle;
        }
    }

    public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException {

        connection.updateLastAccess();
        try {
            proxy.setTimestamp(parameterIndex, x, cal);
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "setTimestamp(int,Timestamp,Calendar)"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "setTimestamp(int,Timestamp,Calendar)");
            throw sqle;
        }
    }

    public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException {

        connection.updateLastAccess();
        try {
            proxy.setTimestamp(parameterIndex, x);
        } catch (SQLException sqle) {
            error(messages.format("DataSource.GeneralMethodError", "setTimestamp(int,Timestamp)"), sqle);
            throw sqle;
        } catch (Throwable t) {
            SQLException sqle = connection.createWrappedSQLException(t, "setTimestamp(int,Timestamp)");
            throw sqle;
        }
    }

    public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException {

        setAsciiStream(parameterIndex, x, length);
    }

    private void logQuery() throws SQLException {

        if (!hasLogged) {
            String nsql = connection.nativeSQL(lastStatement);
            info(messages.format("DataSource.StatementExec", nsql));
            hasLogged = true;
        }
    }
}
